package com.jl.update;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import com.jl.bean.CMD_55AA;
import com.jl.bean.FF;
import com.util.Connection;
import com.util.EncodingUtil;
import com.util.FileTimeSorf;
import com.util.IDEAUtil;

import android.os.Message;
import android_serialport_api.sample.UpgradeActivity;
/**
 * 聚利IAP升级主要信息
 * @author LiuYaDong
 *
 */
public class HardwareUpdate extends Thread {

	public static final String path = UpgradeActivity.path;

	public String KEY_VALUE = "1A70B8BE26C994DA88F4712F5E60C73B";

	public static List<String> list = null;

	public IDEAUtil idea = null;

	private Connection con =  null ;

	private String fileName = "";

	public static String[] strs = null;

	public static String[] isp = null;

	String crc = "";

	public static String countLength = "";

	public static boolean isIdea = false;

	public static int position = 0;

	public HardwareUpdate(){
		try {
			con = new Connection();
		} catch (Exception e) {
			sendMessages(2, "串口连接出现问题");
		}
	}
	public String getFileName() {
		return fileName;
	}

	public void setFileName(String fileName) {
		this.fileName = fileName;
	}

	public boolean IDEADecryption(String path,String fileName) {
		try {
			sendMessages(0,"开始验证文件");
			idea = new IDEAUtil();
			// 文件总大小
			byte[] bytes = getBytes(path + "/" + fileName);
			if (bytes == null) {
				isIdea = false;
				return isIdea;
			}
			String functionDateKey = "1A70B8BE26C994DA88F4712F5E60C73B";
			String functionKey = "";
			strs = new String[(bytes.length - 48) / 8];
			isp = new String[4];
			int i = 0;
			// IDEA解密数据
			for (int j = 0; j < bytes.length / 8; j++) { // 5160
				if (j < 2) {
					functionKey += (idea.decodingCode(functionDateKey,
							EncodingUtil.bytesToHexString(EncodingUtil.subByte(
									j * 8, 4, bytes))));
					//System.err.println("functionKey="+functionKey);
				} else if (j >= (bytes.length / 8) - 4) {
					isp[i] = (idea.decodingCode(functionKey, EncodingUtil
							.bytesToHexString(EncodingUtil.subByte(j * 8, 4,
									bytes))));
					//System.err.println("isp["+i+"]="+isp[i]);
					i++;
				} else {
					strs[j - 2] = (idea.decodingCode(functionKey, EncodingUtil
							.bytesToHexString(EncodingUtil.subByte(j * 8, 4,
									bytes))));
				}
			}
			bytes = null;
			// 得到主程序长度 10进制
			long DateLength = Long.parseLong(EncodingUtil.hexToDec(strs[0]
					.toString().substring(0, 8))) * 2;
			//System.err.println("strs[0]="+strs[0]+", DateLength="+DateLength);
			StringBuffer sb = new StringBuffer();
			StringBuffer CountSB = new StringBuffer();
			// 计算CRC32
			for (int j = 0; j < strs.length; j++) {
				sb.append(strs[j]);
				if (DateLength - CountSB.length() < 1024) {
					//System.err.println("CountSB="+CountSB.length()+", sb="+sb.length());
					// 得到主程序内容还差多少满住主程序长度
					int jiange = (int) (DateLength - CountSB.length());
					if (sb.length() >= jiange + 16) {
						String lastString = sb.substring(0, jiange + 8);
						CountSB.append(lastString);
						crc = sb.substring(jiange + 8, jiange + 16);
						//System.err.println("CountSB="+CountSB.length()+", jiange="+jiange+", sb="+sb
						//		+"\nlastString="+lastString+",crc="+crc);
						String comcrc = idea.compareCRC32(IDEAUtil.poly, 0,
								lastString.length(), lastString, crc, true);
						//System.err.println("文件CRC：" + crc + "计算出CRC：" + comcrc);
						if (crc.equals(comcrc)) {
							sendMessages(0,"文件验证成功!");
							//System.out.println("文件验证成功!");
							isIdea = true;
						} else {
							sendMessages(2,"文件验证失败!");
							//System.err.println("文件CRC比较失败!");
							isIdea = false;
						}
					}
				}
				if (sb.length() >= 1024) {
					//System.err.println("sb="+sb.length());
					idea.compareCRC32(IDEAUtil.poly, 0, sb.length(),
							sb.toString(), "", false);
					CountSB.append(sb);
					sb = new StringBuffer();
				}
			}
			return isIdea;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 下载文件到设备
	 * @throws IOException
	 * @throws SecurityException
	 */
	int isRun = -1;
	public void dow(String path,String fileName) throws SecurityException, IOException {
		boolean isgo = false;
		if(position==0){
			isgo = IDEADecryption(path,fileName);
			position++;
		}else{
			isgo = true;
		}
		if (isgo) {
			String baowen = "";
			String context = "";
			int x = 0;
			int y = 0;

			try {
				if (position == 1) {
					//下发复位指令
					int z = 0;
					try {
						baowen = CMD_55AA.create("FF", "FF").getCMDSTR();
						context = con.send(baowen);
						//System.err.println("复位指令：" + context);
						if (!checkCMD(context)) {

						}else{
							isRun = 0;

						}
					} catch (Exception e) {
						System.out.println("复位异常");
						while (z < 2) {
							z++;
							baowen = new FF().send(x + "D", "07", "");
							//System.err.println("查找指令：" + baowen);
							context = con.read(baowen, 500);
							//System.err.println("查找结果：" + context);
							if (check(context)) {
								isRun = 0;
								break;
							}else{
								if (z == 2) {
									sendMessages(1, "");
									return;
								}
							}
						}
					}
					if (isRun != 0) {
						sendMessages(2,"复位失败!");
						return;
					}
				}
				sendMessages(0,"即将进入编程模式!");

				// 下发07指令进入编程状态
				while (true) {
					baowen = new FF().send(x + "D", "07", "");
					System.err.println("进入编程模式：" + baowen);
					context = con.read(baowen, 80);
					System.err.println("进入编程模式结果：" + context);
					if (check(context)) {

						String a = "";
						for (int j = 0; j < isp.length; j++) {
							a += isp[j];
						}
						String contStr = context.substring(8, 72).toUpperCase();
						String aStr = "";
						System.err.println(a.toUpperCase());
						System.err.println(contStr);
						int nIndex = a.indexOf("FF");
						if (nIndex<0) {
							aStr = a;
						} else{
							aStr = a.substring(0, nIndex);
							contStr = contStr.substring(0, nIndex);
						}
						if (!aStr.toUpperCase().equals(contStr)) {
							sendMessages(2,"升级文件与程序不一致!");
							return;
						}

						isRun = 1;
						break;
					}
					x++;
					if (x == 10) {
						x = 0;
						y++;
						if (y == 130) {
							break;
						}
					}
				}
				if (isRun == 1) {
					sendMessages(0,"查询成功!");
				} else {
					sendMessages(2,"查询失败!");
					return;
				}
				x = 0;
				y = 0;
				// 加密ISP
				String str = ideaEncoding(isp, KEY_VALUE);
				// 下发03指令
				while (true) {
					baowen = new FF().send(x + "D", "03",
							EncodingUtil.desToHex(((strs.length * 16) / 2), 8)
									+ EncodingUtil.addZeor(str, 64));
					// System.err.println("发送03指令：" + baowen);
					context = con.read(baowen, 1000);
					// System.err.println("03指令返回：" + context);
					if (check(context)) {
						isRun = 2;
						break;
					}

					x++;
					if (x == 10) {
						x = 0;
						y++;
						if (y == 20) {
							break;
						}
					}
				}
				if (isRun == 2) {
					sendMessages(0,"身份验证成功,进入下载模式");
				} else {
					sendMessages(2,"身份验证未成功!");
					return;
				}

				x = 0;
				y = 0;

				String functionKeyA = "";
				String functionKeyB = "";
				String functionKey = "";
				String date = "";
				boolean action = true;
				// 是否需要重新生成过程密钥
				int isSend = 0;
				// 次数
				int s = 0;
				// 总数
				int count = (int) Math
						.ceil(((double) (strs.length * 16)) / 160);
				//System.err.println("幀总数：" + count); // 429
				// 发送04下载指令
				String number = "";
				String zhenCount = "";
				String zhenNumber = "";
				String Date = "";
				// 用过程密钥加密数据
				for (int i = 0; i < strs.length; i++) {
					if (isSend == 0) {
						// 生成过程密钥随机数
						functionKeyA = randomNumber(16);
						functionKeyB = randomNumber(16);
						functionKey = functionKeyA + functionKeyB;
					}
					// 拼装80字节数据
					date += idea.encodingCode(functionKey, strs[i]);
					if (date.length() == 160) {
						sendMessages(24,baifenbi(s, count));
						sendMessages(23,"下载进度" + s + "/" + count);
						// 密文字节数
						number = EncodingUtil.desToHex((date.length() / 2) / 8,
								2);
						// 幀总数
						zhenCount = EncodingUtil.desToHex(count, 4);
						// 当前幀数
						zhenNumber = EncodingUtil.inserZero(
								EncodingUtil.desToHex(s), 4);
						// 过程密钥+数据密文

						// IDEA加密随机数生成过程密钥 functionKey
						functionKey = idea
								.encodingCode(KEY_VALUE, functionKeyA);
						functionKey += idea.encodingCode(KEY_VALUE,
								functionKeyB);

						Date = functionKey + addZero(date);

						baowen = new FF().send(y + "D", "04", number
								+ zhenCount + zhenNumber + Date);
						context = con.read(baowen, 3000);
						//System.err.println("04  "+context);
						if (check(context)) {
							x = 0;
							isSend = 0;
							s++;
							action = true;
							date = "";
							isRun = 3;
						} else {
							if (context != null && !"".equals(context)) {
								sendMessages(2,"下载失败!");
								break;
							} else {
								action = false;
							}
						}
						if (action == false) {
							break;
						}
						y++;
						if (y == 9) {
							y = 0;
						}
					} else if (i + 1 == strs.length) {
						sendMessages(24,baifenbi(s, count));
						sendMessages(23,"下载进度" + s + "/" + count);
						number = EncodingUtil.desToHex((date.length() / 2) / 8,
								2);
						zhenCount = EncodingUtil.desToHex(count, 4);
						zhenNumber = EncodingUtil.inserZero(
								EncodingUtil.desToHex(s), 4);

						// IDEA加密随机数生成过程密钥 functionKey
						functionKey = idea
								.encodingCode(KEY_VALUE, functionKeyA);
						functionKey += idea.encodingCode(KEY_VALUE,
								functionKeyB);

						Date = functionKey + addZero(date);
						baowen = new FF().send(y + "D", "04", number
								+ zhenCount + zhenNumber + Date);
						context = con.read(baowen, 3000);
						//System.err.println("04  "+context);
						if (check(context)) {
							x = 0;
							isSend = 0;
							s++;
							action = true;
							date = "";
							isRun = 3;
						} else {
							if (context != null && !"".equals(context)) {
								sendMessages(2,"下载失败!");
								break;
							} else {
								action = false;
							}
						}

						if (action == false) {
							break;
						}
						y++;
						if (y == 9) {
							y = 0;
						}
					} else {
						isSend = 1;
					}
				}
				if (isRun == 2) {
					sendMessages(2,"下载失败!" + s + "/" + count);
					return;
				} else {
					sendMessages(0,"下载文件完成!" + s + "/" + count);
				}

				x = 0;
				y = 0;
				// 下发05指令
				while (true) {
					baowen = new FF().send(x + "D", "05", "");
					//System.out.println("05:"+baowen);
					context = con.read(baowen, 5000);
					if (check(context)) {
						//System.out.println("05:"+context);
						isRun = 4;
						break;
					}
					x++;
					if (x == 10) {
						x = 0;
						y++;
						if (y == 20) {
							break;
						}
					}
				}
				if(isRun == 4){
					sendMessages(0,"程序烧写完成");
				}else{
					sendMessages(2,"程序烧写失败!");
					return;
				}

				//下发06指令
				baowen = new FF().send(x+"D", "06", "");
				//System.out.println("06:"+baowen);
				context = con.read(baowen, 0);
				//System.out.println("06:"+context);
				sendMessages(3,"升级完毕");
				System.out.println("end");
				position = 0;
			} catch (Exception e) {
				e.printStackTrace();
				position = 0;
				sendMessages(2, "出现异常");
				try {
					baowen = new FF().send(x+"D", "06", "");
					con.read(baowen, 0);
				} catch (Exception e1) {
					System.out.println("尝试退出异常");
				}
			}
		} else {
			sendMessages(2,"文件验证失败!");
		}
	}

	/**
	 * 获取随机数
	 *
	 * @param leng
	 *            32
	 * @return
	 */
	public static String randomNumber(int leng) {
		Random random = new Random();
		String s = "";
		for (int i = 0; i < 2; i++) {
			s = s + Integer.toHexString(random.nextInt());
		}
		while (s.length() < leng) {
			s += "0";
		}
		return s.toUpperCase();
	}

	public static void deleteFile(String filePath) {
		File baseDir = new File(filePath);
		if (baseDir.exists()) {
			baseDir.deleteOnExit();
			baseDir.delete();
		}
	}

	/**
	 * 获取排序后的文件列表
	 *
	 * @param filePath
	 */
	public static void fileName(String filePath) {
		// 判断目录是否存在
		list = new ArrayList<String>();
		FileTimeSorf d = new FileTimeSorf(filePath);
		d.init();
		d.sorf();
		d.print();
	}

	/**
	 * 获得指定文件的byte数组
	 */
	public static byte[] getBytes(String filePath) {
		byte[] buffer = null;
		try {
			File file = new File(filePath);

			if (!file.exists()) {
				return null;
			}
			FileInputStream fis = new FileInputStream(file);
			ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
			byte[] b = new byte[1000];
			int n;
			while ((n = fis.read(b)) != -1) {
				bos.write(b, 0, n);
			}
			fis.close();
			bos.close();
			buffer = bos.toByteArray();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return buffer;
	}

	public String arrayToString(String[] str, int k) {
		String date = "";
		for (int i = k; i < str.length; i++) {
			date += str[i];
		}
		return date;
	}

	public String addZero(String str) {
		String s = str;
		while (true) {
			if (s.length() % 8 != 0) {
				s += "00";
			} else {
				return s;
			}
		}
	}

	public String ideaEncoding(String[] strs, String key) {
		if (idea == null) {
			idea = new IDEAUtil();
		}
		String str = "";
		for (int i = 0; i < strs.length; i++) {
			str += idea.encodingCode(key, strs[i]);
		}
		return str;
	}

	public boolean check(String context) {
		if (context != null && !"".contains(context)) {
			if (context.substring(6, 8).equals("00")) {
				return true;
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	public boolean checkCMD(String cmd){
		if(cmd != null && cmd.length()==16){
			if (cmd.substring(10, 14).equals("FF00")) {
				return true;
			} else {
				return false;
			}
		}else
			return false;
	}

	/**
	 * 计算百分比进度条
	 *
	 * @param number1
	 *            小数
	 * @param number2
	 *            总数
	 * @return
	 */
	public String baifenbi(int number1, int number2) {
		double baiy = number1 * 1.0;
		double baiz = number2 * 1.0;
		double fen = baiy / baiz;
		DecimalFormat df1 = new DecimalFormat("##%");
		return df1.format(fen);
	}

	@Override
	public void run() {
		try {
			dow(path,fileName);
		} catch (Exception e) {
			e.printStackTrace();
			sendMessages(2,"错误," + e.getMessage());
		}

	}


	public void sendMessages(int type,String msg){
		Message mes = new Message();
		mes.arg1 = type;
		mes.obj = msg;
		UpgradeActivity.handler.sendMessage(mes);
	}

}
